﻿using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;
using ApiLib.AppStart;
using ApiLib.Common;
using ApiLib.Utils;
using WebDav;

namespace ApiLib.Helpers;

/// <summary>
/// webdav工具类
/// </summary>
public static class WebdavHelper
{
    private static WebDavClient? _webDavClient;
    private static readonly object Lock = new object();
    private static readonly HashSet<string> FoldersPath = new();

    /// <summary>
    /// 默认模块名
    /// </summary>
    private const string DefaultModuleName = "default";

    /// <summary>
    /// 存储根地址
    /// </summary>
    private static string _davRoot = "";

    /// <summary>
    /// 访问路径
    /// </summary>
    private static string _davUrl = "";

    /// <summary>
    /// 非法路径字符
    /// </summary>
    private static readonly char[] InvalidChars = ['|', '/', '?', '%', '#', '"'];

    /// <summary>
    /// 获取webdav对象
    /// </summary>
    /// <returns></returns>
    private static WebDavClient? BuildClient()
    {
        if (_webDavClient == null)
        {
            lock (Lock)
            {
                if (_webDavClient == null)
                {
                    var myConfig = GlobalConfig.AppConfig;
                    if (myConfig != null)
                    {
                        _davRoot = myConfig.WebdavRoot;
                        _davUrl = myConfig.WebdavUrl;
                        var clientParams = new WebDavClientParams
                        {
                            BaseAddress = new Uri(myConfig.WebdavHost),
                            Credentials = new NetworkCredential(myConfig.WebdavUser, myConfig.WebdavPwd)
                        };
                        _webDavClient = new WebDavClient(clientParams);
                    }
                }
            }
        }

        return _webDavClient;
    }

    /// <summary>
    /// 获取webdav客户端
    /// </summary>
    /// <returns></returns>
    /// <exception cref="MyActionException"></exception>
    public static WebDavClient Instance()
    {
        var client = BuildClient();
        if (client == null)
        {
            throw CommonUtil.ActionException("webdav为空");
        }

        return client;
    }

    /// <summary>
    /// 替换所有非法字符
    /// </summary>
    /// <param name="folderName"></param>
    /// <returns></returns>
    private static string SanitizeFolderName(string folderName)
    {
        // 获取Windows系统中不允许的文件名字符
        var invalidFileNameChars = Path.GetInvalidFileNameChars();
        // 添加其他需要替换的字符  
        invalidFileNameChars = invalidFileNameChars.Concat(InvalidChars).ToArray();
        // 遍历所有无效字符，并将其替换为下划线  
        folderName = invalidFileNameChars.Aggregate(folderName, (current, c) => current.Replace(c.ToString(), "_"));
        // 替换末尾的点或空格（如果有的话）  
        folderName = folderName.TrimEnd('.', ' ');
        // 替换可能存在的连续下划线为单个下划线（可选）  
        folderName = Regex.Replace(folderName, @"_+", "_");
        return folderName;
    }

    /// <summary>
    /// 存储
    /// </summary>
    /// <param name="fileName">标题</param>
    /// <param name="stream">流</param>
    /// <returns></returns>
    public static async Task<string> SaveFile(string fileName, Stream stream)
    {
        return await SaveFile(DefaultModuleName, DateTime.Now, fileName, stream);
    }

    /// <summary>
    /// 存储
    /// </summary>
    /// <param name="moduleName">模块名</param>
    /// <param name="fileName">标题</param>
    /// <param name="stream">流</param>
    /// <returns></returns>
    public static async Task<string> SaveFile(string moduleName, string fileName, Stream stream)
    {
        return await SaveFile(moduleName, DateTime.Now, fileName, stream);
    }

    /// <summary>
    /// 存储
    /// </summary>
    /// <param name="moduleName">模块名</param>
    /// <param name="dateTime">日期</param>
    /// <param name="fileName">标题</param>
    /// <param name="stream">流</param>
    /// <returns></returns>
    public static async Task<string> SaveFile(string moduleName, DateTime dateTime, string fileName, Stream stream)
    {
        var client = Instance();
        try
        {
            var folderPath = await client.BuildPath(moduleName, dateTime);
            // 指定HTML文件的完整路径  
            var filePath = $"{folderPath}{SanitizeFolderName(fileName)}";

            // 上传HTML文件到WebDAV服务器  
            var response = await client.PutFile(filePath, stream);
            if (response.IsSuccessful)
            {
                // return filePath.Replace(_davRoot, _davUrl);
                return GetAbsoluteUri(filePath);
            }
        }
        catch (Exception ex)
        {
            WebUtil.LogExp($"存储{moduleName}-{fileName}到webdav报错", ex);
        }

        return "";
    }

    /// <summary>
    /// 数据存储，存储文件
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="text">html内容</param>
    /// <returns></returns>
    public static async Task<string> SaveText(string fileName, string text)
    {
        return await SaveText(DefaultModuleName, DateTime.Now, fileName, text);
    }

    /// <summary>
    /// 数据存储
    /// </summary>
    /// <param name="moduleName">模块名称</param>
    /// <param name="fileName">文件名</param>
    /// <param name="text">html内容</param>
    /// <returns></returns>
    public static async Task<string> SaveText(string moduleName, string fileName, string text)
    {
        return await SaveText(moduleName, DateTime.Now, fileName, text);
    }

    /// <summary>
    /// 数据存储，存储文本
    /// </summary>
    /// <param name="moduleName">模块名称</param>
    /// <param name="dateTime">日期</param>
    /// <param name="fileName">文件名</param>
    /// <param name="text">html内容</param>
    /// <returns></returns>
    public static async Task<string> SaveText(string moduleName, DateTime dateTime, string fileName, string text)
    {
        var client = Instance();
        try
        {
            var folderPath = await client.BuildPath(moduleName, dateTime);
            // 指定HTML文件的完整路径  
            var filePath = $"{folderPath}{SanitizeFolderName(fileName)}";

            //处理html编码
            if (fileName.EndsWith(".html") && (!text.StartsWith("<meta") && !text.StartsWith("<Meta")))
            {
                text = "<meta charset=\"UTF-8\">" + text;
            }

            // 将HTML内容转换为字节流  
            var bytes = Encoding.UTF8.GetBytes(text);
            // 上传HTML文件到WebDAV服务器  
            using var content = new ByteArrayContent(bytes);
            content.Headers.ContentType = new MediaTypeHeaderValue("text/html")
            {
                CharSet = "utf-8" // 指定字符集为UTF-8  
            };
            // 上传HTML文件到WebDAV服务器  
            var response = await client.PutFile(filePath, content);
            if (response.IsSuccessful)
            {
                // return filePath.Replace(_davRoot, _davUrl);
                return GetAbsoluteUri(filePath);
            }
        }
        catch (Exception ex)
        {
            WebUtil.LogExp($"存储{moduleName}-{fileName}到webdav报错", ex);
        }

        return "";
    }

    /// <summary>
    /// 将文件夹移动到服务器
    /// </summary>
    /// <param name="moduleName"></param>
    /// <param name="sourceDirectoryPath"></param>
    /// <param name="destinationDirectoryPath"></param>
    public static async Task MoveDir(string moduleName,string sourceDirectoryPath, string destinationDirectoryPath)
    {
        var client = Instance();
        try
        {
            var originPath = $@"{_davRoot}/{moduleName}/{destinationDirectoryPath}";
            await client.Mkcol(originPath);
            
            var fileInfos = new List<FileInfo>();
            var dir = new DirectoryInfo(sourceDirectoryPath);
            dir.ScanDir(infos => fileInfos.AddRange(infos));
            
            foreach (var file in fileInfos)
            {
                try
                {
                    var netUrl = file.FullName.Replace(dir.FullName, originPath);
                    // 读取文件内容为字节流  
                    var fileContent = await File.ReadAllBytesAsync(file.FullName);
                    using var content = new ByteArrayContent(fileContent);
                    // 上传HTML文件到WebDAV服务器  
                    var response = await client.PutFile(netUrl, content);
                    if (!response.IsSuccessful)
                    {
                        WebUtil.LogExp($"移动文件：{file.FullName}，失败！错误码：{response.StatusCode}");
                    }
                }
                catch(Exception e)
                {
                    WebUtil.LogExp($"移动文件：{file.FullName}，失败！异常：{e.Message}");
                }
            }
        }
        catch (Exception ex)
        {
            WebUtil.LogExp($"存储目录{moduleName}-{sourceDirectoryPath}到webdav报错", ex);
        }
    }
    
    /// <summary>
    /// 获取资源绝对路径
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private static string GetAbsoluteUri(string filePath)
    {
        if (string.IsNullOrEmpty(_davUrl))
        {
            return filePath;
        }

        filePath = filePath.Replace("//", "");
        if (!_davUrl.EndsWith("/") && !filePath.StartsWith("/"))
        {
            filePath = "/" + filePath;
        }

        return _davUrl + filePath;
    }

    /// <summary>
    /// 构建路径
    /// </summary>
    /// <param name="client"></param>
    /// <param name="moduleName">模块名</param>
    /// <param name="dateTime">日期</param>
    /// <returns>路径</returns>
    private static async Task<string> BuildPath(this WebDavClient client, string moduleName, DateTime dateTime)
    {
        var bigPath = $@"{_davRoot}/{moduleName}/";
        if (!FoldersPath.Contains(bigPath))
        {
            await client.Mkcol(bigPath);
            FoldersPath.Add(bigPath);
        }

        var folderPath = $@"{bigPath}{dateTime:yyyy-M-d}/"; // 指定文件下创建文件夹  
        if (!FoldersPath.Contains(folderPath))
        {
            await client.Mkcol(folderPath);
            FoldersPath.Add(folderPath);
        }

        return folderPath;
    }
}